package com.dd.cloud.user.service.plat.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dd.cloud.common.config.common.ProfilesProperties;
import com.dd.cloud.common.config.servlet.JwtUtils;
import com.dd.cloud.common.constants.HealthConstants;
import com.dd.cloud.common.constants.PlatConstants;
import com.dd.cloud.common.constants.UserConstants;
import com.dd.cloud.common.enums.ZkExceptionEnum;
import com.dd.cloud.common.exception.ZekeException;
import com.dd.cloud.common.interceptor.UserInterceptor;
import com.dd.cloud.common.utils.JsonUtils;
import com.dd.cloud.common.vo.LoginInfo;
import com.dd.cloud.user.config.*;
import com.dd.cloud.user.entity.doctor.DoctorDetail;
import com.dd.cloud.user.entity.doctor.DoctorUser;
import com.dd.cloud.user.entity.patient.PatientUser;
import com.dd.cloud.user.entity.plat.PlatformLogin;
import com.dd.cloud.user.entity.plat.PlatformWechatInfo;
import com.dd.cloud.user.entity.wechat.AppletAccessToken;
import com.dd.cloud.user.entity.wechat.WebPageAccessToken;
import com.dd.cloud.user.enums.ExceptionEnum;
import com.dd.cloud.user.mapper.plat.PlatformLoginMapper;
import com.dd.cloud.user.req.patient.BindPatientUserWxReq;
import com.dd.cloud.user.req.plat.PlatBindAccountReq;
import com.dd.cloud.user.req.plat.PlatLoginAccountReq;
import com.dd.cloud.user.res.plat.PlatLoginRes;
import com.dd.cloud.user.res.plat.WxGetTokenRes;
import com.dd.cloud.user.service.doctor.IDoctorDetailService;
import com.dd.cloud.user.service.doctor.IDoctorUserService;
import com.dd.cloud.user.service.file.IFileInfoService;
import com.dd.cloud.user.service.patient.IPatientUserService;
import com.dd.cloud.user.service.plat.IPlatformLoginService;
import com.dd.cloud.user.service.plat.IPlatformWechatInfoService;
import com.dd.cloud.user.util.WxUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 第三方登录信息表 服务实现类
 * </p>
 *
 * @author czg
 * @since 2022-05-06
 */
@Service
@Slf4j
public class PlatformLoginServiceImpl extends ServiceImpl<PlatformLoginMapper, PlatformLogin> implements IPlatformLoginService {
    @Autowired
    private WechatConfig wechatConfig;
    @Autowired
    private WechatPayConfig wechatPayConfig;
    @Autowired
    private WechatAppletConfig wechatAppletConfig;
    @Autowired
    private WechatPatientAppletConfig wechatPatientAppletConfig;
    @Autowired
    private WechatPatientGzhConfig wechatPatientGzhConfig;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private IPlatformWechatInfoService platformWechatInfoService;
    @Autowired
    private IDoctorUserService doctorUserService;
    @Autowired
    private IPatientUserService patientUserService;
    @Autowired
    private IDoctorDetailService doctorDetailService;
    @Autowired
    private JwtUtils jwtUtils;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private IFileInfoService fileInfoService;
    @Autowired
    private ProfilesProperties profilesProperties;

    /**
     * 第三方登录
     *
     * @param req
     * @return
     */
    @Override
    public PlatLoginRes<Object> platLogin(HttpServletRequest request, HttpServletResponse response, PlatLoginAccountReq req) {
        if (req == null){
            throw new ZekeException(ZkExceptionEnum.INVALID_USERNAME_PASSWORD);
        }
        //微信登录判断code
        if (StringUtils.isBlank(req.getCode()) && req.getType() == PlatConstants.PlatType.WX) {
            throw new ZekeException(ZkExceptionEnum.INVALID_USERNAME_PASSWORD);
        }
        int userType = 0;
        //判断登录者的类型
        String userClient = request.getHeader("client");
        switch (userClient) {
            //医生登录
            case HealthConstants.ClientType.HEALTHPC:
                userType = LoginInfo.UserType.DOCTOR;
                break;
            //患者登录
            case HealthConstants.ClientType.HEALTHPATIENT:
                userType = LoginInfo.UserType.PATIENT;
                break;
            default:
        }
        PlatLoginRes<Object> platLoginRes = new PlatLoginRes<>();
        PlatformWechatInfo wechatUserInfo = new PlatformWechatInfo();
        String platId = "";
        /**
         * 第三方登录获取唯一id
         */
        switch (req.getType()) {
            //微信登录
            case PlatConstants.PlatType.WX:
                //获取微信用户信息
                wechatUserInfo = getWechatUserInfo(req.getCode());
                if (wechatUserInfo == null || wechatUserInfo.getOpenid() == null) {
                    return platLoginRes;
                }
                platId = wechatUserInfo.getOpenid();
                break;
            //微信小程序登录
            case PlatConstants.PlatType.WX_APPLET:

                String phoneUrl = String.format(wechatConfig.getGetAppletOpenid(), wechatPatientAppletConfig.getAppId(), wechatPatientAppletConfig.getMchKey(), req.getCode());
                log.info("phoneUrl:{}", phoneUrl);
                String res;
                try {
                    res = restTemplate.postForObject(phoneUrl, null, String.class);
                    log.info("小程序授权返回:{}", res);
                } catch (RestClientException e) {
                    e.printStackTrace();
                    throw new ZekeException(400, "调用微信接口异常");
                }
                JSONObject jsonObject = JSON.parseObject(res);
                if (jsonObject.containsKey("errcode")) {
                    throw new ZekeException("小程序授权失败," + jsonObject.getString("errmsg"));
                }
                //绑定了开放平台,公众号和小程序unionid是一致的
                platId = jsonObject.getString("unionid");
                break;
            //支付宝登录
            case PlatConstants.PlatType.ZFB:
                break;
            default:
        }
        //查询第三方账号
        QueryWrapper<PlatformLogin> ql = new QueryWrapper<>();
        ql.lambda().eq(PlatformLogin::getPlatId, platId).eq(PlatformLogin::getUserType, userType).eq(PlatformLogin::getType, req.getType()).eq(PlatformLogin::getStatus, PlatConstants.PlatStatus.NOMER).orderByDesc(PlatformLogin::getLastLoginDate).last("limit 1");
        PlatformLogin platformLogin = getBaseMapper().selectOne(ql);
        if (platformLogin != null) {
            platLoginRes.setPlatformLogin(platformLogin);
        }
        if (req.getType() == PlatConstants.PlatType.WX) {
            //获取微信用户信息
            platLoginRes.setWechatUserInfo(wechatUserInfo);
        }
        if (platformLogin == null) {
            return platLoginRes;
        }
        switch (userType) {
            //医生登录
            case LoginInfo.UserType.DOCTOR:
                DoctorUser doc = doctorUserService.getById(platformLogin.getUserId());
                if (doc == null) {
                    return platLoginRes;
                }
                doctorUserService.switchStatus(doc);
                QueryWrapper<DoctorDetail> qw = new QueryWrapper<>();
                qw.lambda().eq(DoctorDetail::getDoctorId, doc.getId()).eq(DoctorDetail::getStatus, UserConstants.DoctorDetailStatus.NORMAL);
                DoctorDetail doctorDetail = doctorDetailService.getOne(qw);
                jwtUtils.createToken(new LoginInfo(doc.getId(), doc.getMechanId(), LoginInfo.UserType.DOCTOR, doctorDetail.getName(), platId), request, response);
                platLoginRes.setUser(doc);
                platLoginRes.setStatus(1);
                break;
            //患者登录
            case LoginInfo.UserType.PATIENT:
                PatientUser patientUser = patientUserService.getById(platformLogin.getUserId());
                if (patientUser == null) {
                    return platLoginRes;
                }
                jwtUtils.createToken(new LoginInfo(patientUser.getId(), 0, LoginInfo.UserType.PATIENT, patientUser.getNickName(), platId), request, response);
                platLoginRes.setUser(patientUser);
                platLoginRes.setStatus(1);
                platformLogin.setLastLoginDate(LocalDateTime.now());
                updateById(platformLogin);
                break;
            default:
        }
        return platLoginRes;
    }

    /**
     * 第三方登录自动绑定账号
     *
     * @param req
     * @return 1绑定成功 0绑定失败 2已有绑定账号且不是当前账号
     */
    @Override
    public Integer bindAccountPlat(HttpServletResponse response, PlatBindAccountReq req) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        if (loginInfo == null && req.getUserId() == null) {
            return 0;
        }
        if (loginInfo != null && req.getUserId() == null) {
            req.setUserId(loginInfo.getId());
            req.setUserType(loginInfo.getType());
        }
        QueryWrapper<PlatformLogin> q2 = new QueryWrapper<>();
        q2.lambda().eq(PlatformLogin::getUserId, req.getUserId());
        q2.lambda().eq(PlatformLogin::getUserType, req.getUserType());
        q2.lambda().eq(PlatformLogin::getType, req.getType());
        q2.lambda().eq(PlatformLogin::getStatus, PlatConstants.PlatStatus.NOMER);
        PlatformLogin p = getBaseMapper().selectOne(q2);
        if (p != null) {
            if (!p.getPlatId().equals(req.getPlatId())) {
                //此次第三方登录对应的账户不是之前绑定的账户
                log.info("第三方id不一致platid={},openid={}", p.getPlatId(), req.getPlatId());
                return 2;
            }
            return 1;
        }
        UpdateWrapper<PlatformLogin> qu = new UpdateWrapper<>();
        qu.lambda().eq(PlatformLogin::getPlatId, req.getPlatId());
        qu.lambda().eq(PlatformLogin::getUserType, req.getUserType());
        qu.lambda().ne(PlatformLogin::getStatus, PlatConstants.PlatStatus.DEL);
        PlatformLogin platformLogin = new PlatformLogin();
        BeanUtils.copyProperties(req, platformLogin);
        platformLogin.setUserType(req.getUserType());
        platformLogin.setUserId(req.getUserId());
        platformLogin.setCreateDate(LocalDateTime.now());
        platformLogin.setStatus(PlatConstants.PlatStatus.NOMER);
        platformLogin.setPlatId(req.getPlatId());
        platformLogin.setLastLoginDate(LocalDateTime.now());
        boolean i = saveOrUpdate(platformLogin, qu);
        if (!i) {
            return 0;
        }
        return 1;
    }

    /**
     * 微信登录第一步, 获取微信二维码链接
     *
     * @return
     */
    @Override
    public String wxLoginurl(String url) {
        String redirect_uri = "";
        try {
            redirect_uri = URLEncoder.encode(url, "UTF-8");
        } catch (Exception e) {

        }
        redirect_uri = String.format(wechatConfig.getGetwxLoginUrl(), wechatPayConfig.getAppId(), redirect_uri);
        return redirect_uri;
    }

    /**
     * 微信登录第二步, 通过code获取access_token 并登录
     *
     * @return
     */
    @Override
    public PlatLoginRes getAcTokenByCode(HttpServletRequest request, HttpServletResponse response, PlatLoginAccountReq req) {
        if (req.getCode() == null) {
            throw new ZekeException(400, "code不能为空");
        }
        String url = String.format(wechatConfig.getWebPageAuthorizationAccessTokenUrl(), wechatPayConfig.getAppId(), wechatPayConfig.getMchKey(), req.getCode());
        log.info(url + "");
        String result = restTemplate.getForObject(url, String.class);
        log.info(result + "");
        WxGetTokenRes wxGetTokenRes = JSONObject.parseObject(result, WxGetTokenRes.class);
        PlatLoginRes platLoginRes = new PlatLoginRes<>();
        platLoginRes.setStatus(0);
        if (wxGetTokenRes.getUnionid() == null) {
            platLoginRes.setMsg(wxGetTokenRes.getErrmsg());
            return null;
        }
        int userType = 0;
        //判断登录者的类型
        String userClient = request.getHeader("client");
        switch (userClient) {
            //医生登录
            case HealthConstants.ClientType.HEALTHPC:
                userType = LoginInfo.UserType.DOCTOR;
                break;
        }
        PlatformWechatInfo wechatUserInfo = new PlatformWechatInfo();
        String platId = "";
        /**
         * 第三方登录获取唯一id
         */
        switch (req.getType()) {
            //微信登录
            case PlatConstants.PlatType.WX:
                //获取微信用户信息
                WebPageAccessToken webPageAccessToken = new WebPageAccessToken();
                webPageAccessToken.setOpenid(wxGetTokenRes.getOpenid());
                webPageAccessToken.setAccess_token(wxGetTokenRes.getAccess_token());
                webPageAccessToken.setRefresh_token(wxGetTokenRes.getRefresh_token());
                webPageAccessToken.setType(PlatConstants.UserType.OPENPLAT);
                wechatUserInfo = getWechatUserInfo(webPageAccessToken);
                if (wechatUserInfo == null || wechatUserInfo.getOpenid() == null) {
                    platLoginRes.setMsg("微信用户信息获取失败");
                    return platLoginRes;
                }
                platId = wechatUserInfo.getUnionid();
                break;
            //支付宝登录
            case PlatConstants.PlatType.ZFB:
                break;
        }

        //查询第三方账号
        QueryWrapper<PlatformLogin> ql = new QueryWrapper<>();
        ql.lambda().eq(PlatformLogin::getPlatId, platId);
        ql.lambda().eq(PlatformLogin::getUserType, userType);
        ql.lambda().eq(PlatformLogin::getType, req.getType());
        ql.lambda().eq(PlatformLogin::getStatus, PlatConstants.PlatStatus.NOMER);
        PlatformLogin platformLogin = getBaseMapper().selectOne(ql);
        if (platformLogin != null) {
            platLoginRes.setPlatformLogin(platformLogin);
        }
        if (req.getType() == PlatConstants.PlatType.WX) {
            //获取微信用户信息
            platLoginRes.setWechatUserInfo(wechatUserInfo);
        }
        platLoginRes.setStatus(2);
        if (platformLogin == null) {
            platLoginRes.setMsg("当前微信未绑定账号,请输入账号密码登录后自动绑定");
            return platLoginRes;
        }
        switch (userType) {
            //医生登录
            case LoginInfo.UserType.DOCTOR:
                DoctorUser doc = doctorUserService.getById(platformLogin.getUserId());
                if (doc == null) {
                    throw new ZekeException(ZkExceptionEnum.ACCOUNT_NOT_FOUND);
                }
                doctorUserService.switchStatus(doc);
                QueryWrapper<DoctorDetail> qw = new QueryWrapper<>();
                qw.lambda().eq(DoctorDetail::getDoctorId, doc.getId()).eq(DoctorDetail::getStatus, UserConstants.DoctorDetailStatus.NORMAL);
                DoctorDetail doctorDetail = doctorDetailService.getOne(qw);
                jwtUtils.createToken(new LoginInfo(doc.getId(), doc.getMechanId(), LoginInfo.UserType.DOCTOR, doctorDetail.getName(), platId), request, response);
                platLoginRes.setUser(doc);
                platLoginRes.setStatus(1);
                break;

        }
        return platLoginRes;
    }

    /**
     * 微信刷新token
     *
     * @param code
     * @return
     */
    @Override
    public WxGetTokenRes refreshToken(String code) {
        return null;
    }

    @Override
    public String getAccessToken() {
        String url = String.format(wechatConfig.getGetwxAccessToken(), wechatPayConfig.getAppId(), wechatPayConfig.getMchKey());
        log.info(url + "");
        String accessToken;
        try {
            String result = restTemplate.getForObject(url, String.class);
            Map<String, String> map = JsonUtils.parseMap(result, String.class, String.class);
            log.info("获取普通的微信token返回:" + map);
            String code = map.get("errcode");
            if (!StringUtils.isBlank(code) && !code.equals("0")) {
                throw new ZekeException(ExceptionEnum.SHART_WX_ERROR, "微信请求token失败" + map.get("errmsg"));
            }
            accessToken = map.get("access_token");
        } catch (Exception e) {
            e.printStackTrace();
            throw new ZekeException(ExceptionEnum.SHART_WX_ERROR, "获取微信token失败");
        }
        return accessToken;
    }

    @Override
    public WxMaService getWxMaService(Integer userType) {
        WxMaService wxService = null;
        if (userType == LoginInfo.UserType.PATIENT) {
            wxService = WxMaConfiguration.getMaService(wechatPatientAppletConfig.getAppId());
        } else if (userType == LoginInfo.UserType.DOCTOR) {
            wxService = WxMaConfiguration.getMaService(wechatAppletConfig.getAppId());
        } else {
            //默认返回用户
            wxService = WxMaConfiguration.getMaService(wechatPatientAppletConfig.getAppId());
        }
        return wxService;
    }


    /**
     * 获取微信openId
     *
     * @param response
     * @param code
     * @param appId
     * @return
     */
    @Override
    public PlatformWechatInfo getWechatOpenid(HttpServletResponse response, String code, String appId) {
        PlatformWechatInfo platformWechatInfo = getWechatUserInfo(code);
        QueryWrapper<PlatformLogin> qw = new QueryWrapper<>();
        qw.lambda().eq(PlatformLogin::getPlatId, platformWechatInfo.getOpenid());
        qw.lambda().eq(PlatformLogin::getStatus, PlatConstants.PlatStatus.NOMER);
        PlatformLogin platformLogin = getOne(qw);
        if (platformLogin != null) {
//            platformWechatInfo.setBind(1);
        }
        return platformWechatInfo;
    }

    /**
     * 解绑账号
     */
    @Override
    public void unbindAccountWx() {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        QueryWrapper<PlatformLogin> q2 = new QueryWrapper<>();
        q2.lambda().eq(PlatformLogin::getUserId, loginInfo.getId());
        q2.lambda().eq(PlatformLogin::getUserType, loginInfo.getType());
        q2.lambda().eq(PlatformLogin::getType, 1);
        q2.lambda().eq(PlatformLogin::getStatus, PlatConstants.PlatStatus.NOMER);
        PlatformLogin platformLogin = getBaseMapper().selectOne(q2);
        if (platformLogin == null) {
            throw new ZekeException(400, "微信解绑失败");
        }
        PlatformLogin update = new PlatformLogin();
        update.setId(platformLogin.getId());
        update.setStatus(PlatConstants.PlatStatus.DEL);
        boolean flag = updateById(update);
        if (!flag) {
            throw new ZekeException(400, "微信解绑失败");
        }
    }

    /**
     * @param :
     * @return WechatAppletConfig
     * @description 获取小程序配置
     * @author czg
     * @date 2023/5/23 17:56
     */
    @Override
    public String getAppletConfig(String code) {
        WechatAppletConfig config = new WechatAppletConfig();
        BeanUtils.copyProperties(wechatAppletConfig, config);
        String url = String.format(wechatConfig.getGetAppletOpenid(), wechatAppletConfig.getAppId(), wechatAppletConfig.getMchKey(), code);
        log.info(url + "");
        String result = restTemplate.getForObject(url, String.class);
        JSONObject jsonObject = JSONObject.parseObject(result);
        log.info("小程序登录返回:" + jsonObject);
        if (jsonObject.get("errcode") != null) {
            String msg = jsonObject.getString("errmsg");
            throw new ZekeException(ZkExceptionEnum.APPLET_LOGIN_ERROR, msg);
        }
        String openid = jsonObject.getString("openid");
        return openid;
    }

    @Override
    public String getDoctorAccessToken() {
        String url = String.format(wechatConfig.getGetwxAccessToken(), wechatAppletConfig.getAppId(), wechatAppletConfig.getMchKey());
        log.info(url + "");
        String accessToken;
        try {
            String result = restTemplate.getForObject(url, String.class);
            Map<String, String> map = JsonUtils.parseMap(result, String.class, String.class);
            log.info("获取普通的微信token返回:" + map);
            String code = map.get("errcode");
            if (!StringUtils.isBlank(code) && !code.equals("0")) {
                throw new ZekeException(ExceptionEnum.SHART_WX_ERROR, "微信请求token失败" + map.get("errmsg"));
            }
            accessToken = map.get("access_token");
        } catch (Exception e) {
            e.printStackTrace();
            throw new ZekeException(ExceptionEnum.SHART_WX_ERROR, "获取微信token失败");
        }
        return accessToken;
    }

    @Override
    public String getPatientUserAccessToken() {
        String url = String.format(wechatConfig.getGetwxAccessToken(), wechatPatientAppletConfig.getAppId(), wechatPatientAppletConfig.getMchKey());
        log.info(url + "");
        String accessToken;
        try {
            String result = restTemplate.getForObject(url, String.class);
            Map<String, String> map = JsonUtils.parseMap(result, String.class, String.class);
            log.info("获取普通的微信token返回:" + map);
            String code = map.get("errcode");
            if (!StringUtils.isBlank(code) && !code.equals("0")) {
                throw new ZekeException(ExceptionEnum.SHART_WX_ERROR, "微信请求token失败" + map.get("errmsg"));
            }
            accessToken = map.get("access_token");
        } catch (Exception e) {
            e.printStackTrace();
            throw new ZekeException(ExceptionEnum.SHART_WX_ERROR, "获取微信token失败");
        }
        return accessToken;
    }

    /**
     * 获取用户端token
     *
     * @return String
     */
    @Override
    public String getPatientUserGzhAccessToken() {
        String url = String.format(wechatConfig.getGetwxAccessToken(), wechatPatientGzhConfig.getAppId(), wechatPatientGzhConfig.getMchKey());
        log.info(url + "");
        String accessToken;
        try {
            String result = restTemplate.getForObject(url, String.class);
            Map<String, String> map = JsonUtils.parseMap(result, String.class, String.class);
            log.info("获取普通的微信token返回:" + map);
            String code = map.get("errcode");
            if (!StringUtils.isBlank(code) && !code.equals("0")) {
                throw new ZekeException(ExceptionEnum.SHART_WX_ERROR, "微信请求token失败" + map.get("errmsg"));
            }
            accessToken = map.get("access_token");
        } catch (Exception e) {
            e.printStackTrace();
            throw new ZekeException(ExceptionEnum.SHART_WX_ERROR, "获取微信token失败");
        }
        return accessToken;
    }

    /**
     * 获取微信授权token
     *
     * @param appid
     * @param mchKey
     * @return
     */
    public String getAccessToken(String appid, String mchKey) {
        String url = String.format(wechatConfig.getGetwxAccessToken(), appid, mchKey);
        log.info(url + "");
        String accessToken;
        try {
            String result = restTemplate.getForObject(url, String.class);
            Map<String, String> map = JsonUtils.parseMap(result, String.class, String.class);
            log.info("获取普通的微信token返回:" + map);
            String code = map.get("errcode");
            if (!StringUtils.isBlank(code) && !code.equals("0")) {
                throw new ZekeException(ExceptionEnum.SHART_WX_ERROR, "微信请求token失败" + map.get("errmsg"));
            }
            accessToken = map.get("access_token");
        } catch (Exception e) {
            e.printStackTrace();
            throw new ZekeException(ExceptionEnum.SHART_WX_ERROR, "获取微信token失败");
        }
        return accessToken;
    }

    /**
     * 微信接口获取微信用户信息
     *
     * @return
     */
    public PlatformWechatInfo getWechatUserInfo(WebPageAccessToken webPageAccessToken) {
        log.info(webPageAccessToken + "");
        String url = String.format(wechatConfig.getGetAuthUserInfoUrl(), webPageAccessToken.getAccess_token(), webPageAccessToken.getOpenid());
        log.info(url + "");
        String result = restTemplate.getForObject(url, String.class);
        JSONObject jsonObject = JSONObject.parseObject(result);
        log.info("微信返回:" + jsonObject);
        PlatformWechatInfo wechatUserInfo = new PlatformWechatInfo();
        wechatUserInfo.setCity(jsonObject.getString("city"));
        wechatUserInfo.setCountry(jsonObject.getString("country"));
        wechatUserInfo.setHeadimgurl(jsonObject.getString("headimgurl"));
        wechatUserInfo.setLanguage(jsonObject.getString("language"));
        wechatUserInfo.setNickname(jsonObject.getString("nickname"));
        wechatUserInfo.setOpenid(jsonObject.getString("openid"));
        wechatUserInfo.setProvince(jsonObject.getString("province"));
        wechatUserInfo.setSex(jsonObject.getString("sex"));
        wechatUserInfo.setUnionid(jsonObject.getString("unionid"));
        wechatUserInfo.setAccessToken(webPageAccessToken.getAccess_token());
        wechatUserInfo.setRefreshToken(webPageAccessToken.getRefresh_token());
        wechatUserInfo.setType(webPageAccessToken.getType());
        wechatUserInfo.setCreateDate(LocalDateTime.now());
        wechatUserInfo.setAppid(wechatPayConfig.getAppId());
        /**
         * 获取普通access_token 非授权的token,
         * 普通access_token为全局凭证,2个小时有效期,是开发者调用各种接口的凭证
         * 授权的access_token只能用来获取用户授权的基本信息,无法调用其他接口
         */
        String accessToken = "";
        try {
            accessToken = getAccessToken();
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (StringUtils.isBlank(accessToken)) {
            wechatUserInfo.setInvalidDate(LocalDateTime.now());
        } else {
            wechatUserInfo.setAccessToken(accessToken);
            wechatUserInfo.setInvalidDate(LocalDateTime.now().plusSeconds(2L));
        }
        UpdateWrapper<PlatformWechatInfo> qu = new UpdateWrapper<>();
        if (wechatUserInfo.getUnionid() == null) {
            qu.lambda().isNull(PlatformWechatInfo::getUnionid);
        } else {
            qu.lambda().eq(PlatformWechatInfo::getUnionid, wechatUserInfo.getUnionid());
        }
        qu.lambda().eq(PlatformWechatInfo::getOpenid, wechatUserInfo.getOpenid());
        platformWechatInfoService.saveOrUpdate(wechatUserInfo, qu);
        log.info("获取微信用户信息返回:" + wechatUserInfo);
        return wechatUserInfo;
    }

    /**
     * 获取微信用户信息
     */
    public PlatformWechatInfo getWechatUserInfo(String code) {
        String url = String.format(wechatConfig.getWebPageAuthorizationAccessTokenUrl(), wechatPayConfig.getAppId(), wechatPayConfig.getMchKey(), code);
        log.info(url + "");
        String result = restTemplate.getForObject(url, String.class);
        JSONObject jsonObject = JSONObject.parseObject(result);
        log.info("返回:" + jsonObject);
        WebPageAccessToken webPageAccessToken = new WebPageAccessToken();
        webPageAccessToken.setOpenid(jsonObject.getString("openid"));
        webPageAccessToken.setAccess_token(jsonObject.getString("access_token"));
        webPageAccessToken.setRefresh_token(jsonObject.getString("refresh_token"));
        webPageAccessToken.setType(PlatConstants.UserType.PUBLICPLAT);
        PlatformWechatInfo wechatUserInfo = getWechatUserInfo(webPageAccessToken);
        if (wechatUserInfo == null) {
            throw new ZekeException(ZkExceptionEnum.WX_USER_INFO_FAIL);
        }
        log.info("微信获取用户信息=" + wechatUserInfo);
        return wechatUserInfo;
    }

    /**
     * 绑定微信小程序用户
     *
     * @param code
     * @param userId
     * @param userType
     * @return 1绑定成功 0绑定失败 2已有绑定账号且不是当前账号
     */
    @Override
    public Integer bindAppletUser(String code, Integer userId, Integer userType) {
        PlatformWechatInfo info = getWechatUserInfoApplet(code);
        QueryWrapper<PlatformLogin> qw = new QueryWrapper<>();
        qw.lambda().eq(PlatformLogin::getUserId, userId);
        qw.lambda().eq(PlatformLogin::getUserType, userType);
        qw.lambda().ne(PlatformLogin::getStatus, PlatConstants.PlatStatus.DEL);
        PlatformLogin platformLogin = getOne(qw);
        if (platformLogin != null) {
            if (!platformLogin.getPlatId().equals(info.getOpenid())) {
                return 2;
            }
            return 1;
        }
        platformLogin = new PlatformLogin();
        platformLogin.setUserId(userId);
        platformLogin.setUserType(userType);
        platformLogin.setPlatId(info.getOpenid());
        platformLogin.setStatus(PlatConstants.PlatStatus.NOMER);
        platformLogin.setCreateDate(LocalDateTime.now());
        platformLogin.setLastLoginDate(LocalDateTime.now());
        boolean flag = save(platformLogin);
        if (!flag) {
            return 0;
        }
        return 1;
    }

    /**
     * 获取微信用户信息 小程序
     */
    public PlatformWechatInfo getWechatUserInfoApplet(String code) {
        String url = String.format(wechatConfig.getAppletUserLogin(), wechatAppletConfig.getAppId(), wechatAppletConfig.getMchKey(), code);
        log.info(url + "");
        String result = restTemplate.getForObject(url, String.class);
        JSONObject jsonObject = JSONObject.parseObject(result);
        log.info("返回:" + jsonObject);
        AppletAccessToken appletAccessToken = new AppletAccessToken();
        appletAccessToken.setOpenid(jsonObject.getString("openid"));
        appletAccessToken.setUnionid(jsonObject.getString("unionid"));
        appletAccessToken.setErrmsg(jsonObject.getString("errmsg"));
        appletAccessToken.setErrcode(jsonObject.getInteger("errcode"));
        appletAccessToken.setSession_key(jsonObject.getString("session_key"));
        QueryWrapper<PlatformWechatInfo> qw = new QueryWrapper<>();
        qw.lambda().eq(PlatformWechatInfo::getAppid, wechatAppletConfig.getAppId());
        if (appletAccessToken.getUnionid() == null) {
            qw.lambda().isNull(PlatformWechatInfo::getUnionid);
        } else {
            qw.lambda().eq(PlatformWechatInfo::getUnionid, appletAccessToken.getUnionid());
        }
        qw.lambda().eq(PlatformWechatInfo::getOpenid, appletAccessToken.getOpenid());
        PlatformWechatInfo wechatUserInfo = platformWechatInfoService.getOne(qw);
        if (wechatUserInfo == null) {
            wechatUserInfo = new PlatformWechatInfo();
            wechatUserInfo.setAppid(wechatPayConfig.getAppId());
            wechatUserInfo.setOpenid(appletAccessToken.getOpenid());
            wechatUserInfo.setUnionid(appletAccessToken.getUnionid());
            wechatUserInfo.setType(PlatConstants.UserType.APPLET);
            wechatUserInfo.setCreateDate(LocalDateTime.now());
            platformWechatInfoService.save(wechatUserInfo);
        }
        log.info("微信获取用户信息=" + wechatUserInfo);
        return wechatUserInfo;
    }

    /**
     * 患者端小程序未授权, 通过code获取手机号和用户信息,添加用户并授权
     *
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PlatLoginRes<?> getWechatUserInfoAppletPhone(BindPatientUserWxReq req, HttpServletRequest request, HttpServletResponse response) {
        //String accessToken = getDoctorAccessToken();
        PlatLoginRes<Object> platLoginRes = new PlatLoginRes<>();
        PlatformWechatInfo platformWechatInfo = new PlatformWechatInfo();
        String phoneUrl = String.format(wechatConfig.getGetAppletOpenid(), wechatPatientAppletConfig.getAppId(), wechatPatientAppletConfig.getMchKey(), req.getCode());
        log.info("phoneUrl:{}", phoneUrl);

        //HttpEntity<String> entity = new HttpEntity();
        String res;
        try {
            res = restTemplate.postForObject(phoneUrl, null, String.class);
            log.info("小程序授权返回:{}", res);
        } catch (RestClientException e) {
            e.printStackTrace();
            throw new ZekeException(400, "调用微信接口异常");
        }
        JSONObject jsonObject = JSON.parseObject(res);
        if (jsonObject.containsKey("errcode")) {
            throw new ZekeException("小程序授权失败," + jsonObject.getString("errmsg"));
        }
        String platId = jsonObject.getString("openid");
        platformWechatInfo.setOpenid(platId);
        String sessionKey = jsonObject.getString("session_key");
        String phone = null;
        Map<String, String> wxMiniPhone = new HashMap<>();
        try {
            wxMiniPhone = WxUtil.getWxMiniPhone(sessionKey, req.getIv(), req.getEncryptedData());
            log.info("小程序用户信息:{}", wxMiniPhone);
            phone = wxMiniPhone.get("phoneNumber");
            log.info("获取小程序手机号:{}", phone);
        } catch (Exception e) {
            log.info("小程序手机号获取失败");
            e.printStackTrace();
        }

        if (StringUtils.isBlank(phone)) {
            throw new ZekeException("小程序手机号获取失败");
        }

        QueryWrapper<PatientUser> ws = new QueryWrapper<>();
        ws.lambda().eq(PatientUser::getMobileNumber, phone).eq(PatientUser::getStatus, UserConstants.PatientUserStatus.NORMAL).select(PatientUser::getId, PatientUser::getNickName, PatientUser::getMobileNumber);
        PatientUser patientUser = patientUserService.getOne(ws);
        platLoginRes.setWechatUserInfo(platformWechatInfo);
        platLoginRes.setUser(patientUser);
        platLoginRes.setStatus(1);
        if (patientUser != null) {
            //已经存在用户手机账号, 查询添加绑定关系
            //查询第三方账号
            QueryWrapper<PlatformLogin> ql = new QueryWrapper<>();
            ql.lambda().eq(PlatformLogin::getPlatId, platformWechatInfo.getOpenid()).eq(PlatformLogin::getUserType, LoginInfo.UserType.PATIENT).eq(PlatformLogin::getUserId, patientUser.getId()).eq(PlatformLogin::getType, PlatConstants.PlatType.WX_APPLET).eq(PlatformLogin::getStatus, PlatConstants.PlatStatus.NOMER);
            PlatformLogin platformLogin = getBaseMapper().selectOne(ql);
            if (platformLogin != null) {
                //已经有绑定关系
                platLoginRes.setPlatformLogin(platformLogin);
                jwtUtils.createToken(new LoginInfo(patientUser.getId(), 0, LoginInfo.UserType.PATIENT, patientUser.getNickName(), platId), request, response);
                return platLoginRes;
            }
            platformLogin = new PlatformLogin();
            platformLogin.setUserId(patientUser.getId());
            platformLogin.setUserType(LoginInfo.UserType.PATIENT);
            platformLogin.setPlatId(platformWechatInfo.getOpenid());
            platformLogin.setType(PlatConstants.PlatType.WX_APPLET);
            platformLogin.setStatus(PlatConstants.PlatStatus.NOMER);
            platformLogin.setCreateDate(LocalDateTime.now());
            platformLogin.setLastLoginDate(LocalDateTime.now());
            platformLogin.setTitle("小程序登录");
            boolean save = save(platformLogin);
            if (!save) {
                throw new ZekeException("小程序登录失败");
            }
            platLoginRes.setPlatformLogin(platformLogin);
            jwtUtils.createToken(new LoginInfo(patientUser.getId(), 0, LoginInfo.UserType.PATIENT, patientUser.getNickName(), platId), request, response);
            return platLoginRes;
        }

        patientUser = new PatientUser();
        patientUser.setMobileNumber(phone);
        patientUser.setNickName(wxMiniPhone.get("nickName"));
        patientUser.setAvatar(wxMiniPhone.get("avatarUrl"));
        patientUser.setStatus(UserConstants.PatientUserStatus.NORMAL);
        patientUser.setCreateDate(LocalDateTime.now());
        boolean save = patientUserService.save(patientUser);
        if (!save) {
            throw new ZekeException("用户创建失败");
        }
        platLoginRes.setUser(patientUser);
        QueryWrapper<PlatformLogin> ql = new QueryWrapper<>();
        ql.lambda().eq(PlatformLogin::getPlatId, platformWechatInfo.getOpenid()).eq(PlatformLogin::getUserType, LoginInfo.UserType.PATIENT).eq(PlatformLogin::getUserId, patientUser.getId()).eq(PlatformLogin::getType, PlatConstants.PlatType.WX_APPLET).eq(PlatformLogin::getStatus, PlatConstants.PlatStatus.NOMER);
        PlatformLogin platformLogin = getBaseMapper().selectOne(ql);
        if (platformLogin != null) {
            //已经有绑定关系
            platLoginRes.setPlatformLogin(platformLogin);
            jwtUtils.createToken(new LoginInfo(patientUser.getId(), 0, LoginInfo.UserType.PATIENT, patientUser.getNickName(), platId), request, response);
            return platLoginRes;
        }
        platformLogin = new PlatformLogin();
        platformLogin.setUserId(patientUser.getId());
        platformLogin.setUserType(LoginInfo.UserType.PATIENT);
        platformLogin.setPlatId(platformWechatInfo.getOpenid());
        platformLogin.setType(PlatConstants.PlatType.WX_APPLET);
        platformLogin.setStatus(PlatConstants.PlatStatus.NOMER);
        platformLogin.setCreateDate(LocalDateTime.now());
        platformLogin.setLastLoginDate(LocalDateTime.now());
        platformLogin.setTitle("小程序登录");
        boolean save2 = save(platformLogin);
        if (!save2) {
            throw new ZekeException("小程序登录失败");
        }
        platLoginRes.setPlatformLogin(platformLogin);
        jwtUtils.createToken(new LoginInfo(patientUser.getId(), 0, LoginInfo.UserType.PATIENT, patientUser.getNickName(), platId), request, response);
        return platLoginRes;
        //return jsonObject.getJSONObject("phone_info").getString("phoneNumber");
    }

    @Override
    public String getUserAppletConfig(String code) {
        String url = String.format(wechatConfig.getGetAppletOpenid(), wechatPatientAppletConfig.getAppId(), wechatPatientAppletConfig.getMchKey(), code);
        log.info(url + "");
        String result = restTemplate.getForObject(url, String.class);
        JSONObject jsonObject = JSONObject.parseObject(result);
        log.info("小程序登录返回:" + jsonObject);
        if (jsonObject.get("errcode") != null) {
            String msg = jsonObject.getString("errmsg");
            throw new ZekeException(ZkExceptionEnum.APPLET_LOGIN_ERROR, msg);
        }
        String openid = jsonObject.getString("openid");
        return openid;
    }

    @Override
    public String getWxQr(String page, String param) {
        String active = profilesProperties.getActive();
        String accessToken = this.getPatientUserAccessToken();
        MultipartFile multipartFile = WxUtil.getQRCode(param, accessToken, page, active);
        String key = fileInfoService.uploadSingleFileStr(multipartFile, false);
        return key;
    }

    /**
     * 获取患者公众号二维码 用于扫码填写就诊卡
     *
     * @return
     */
    @Override
    public String getPatientGZHWxQr(Integer docId, String param) {
        if (docId == null) {
            LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.DOCTOR).get();
            docId = loginInfo.getId();
        }
        String accessToken = this.getAccessToken(wechatPayConfig.getAppId(), wechatPayConfig.getMchKey());
        WxUtil.WxQrCodeParam wxQrCodeParam = new WxUtil.WxQrCodeParam();
        //type1 填写就诊卡
        wxQrCodeParam.setType(1);
        wxQrCodeParam.setDoctorId(docId);
        wxQrCodeParam.setParam(param);
        String url = WxUtil.createGuidanceQrCode(wxQrCodeParam, accessToken, false);
        return url;
    }
}
